package com.strongbj.iot.devices.hr.response.coder;

import com.strongbj.iot.devices.hr.message.HRMessage;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

/**
 * HR数据解析类，用户接收网络数据并转成HRMessage格式实体
 * 
 * @author yuzhantao
 *
 */
public class HRDecoder extends LengthFieldBasedFrameDecoder {
	// 头部起始码 0x5a 0xa5
	private static final int HEADER_SIZE = 6;
	// 校验码长度
	private static final int BCC_SIZE = 1;

	/**
	 * 协议头
	 */
	private byte header;
	/**
	 * 用于区分各个操作的指令
	 */
	private byte command;
	/**
	 * 指令序列号(PC->读写器 0x00,读写器->PC 0x01)
	 */
	private byte sequence;
	/**
	 * 指令操作码 0xXX 协议预留字节(在 485 通讯中可当作设备地址使用)
	 */
	private byte opcode;
	/**
	 * 数据长度
	 */
	private short dataLen;
	/**
	 * 数据
	 */
	private byte[] data = new byte[0];

	/**
	 * 
	 * @param maxFrameLength
	 *            解码时，处理每个帧数据的最大长度
	 * @param lengthFieldOffset
	 *            该帧数据中，存放该帧数据的长度的数据的起始位置
	 * @param lengthFieldLength
	 *            记录该帧数据长度的字段本身的长度
	 * @param lengthAdjustment
	 *            修改帧数据长度字段中定义的值，可以为负数
	 * @param initialBytesToStrip
	 *            解析的时候需要跳过的字节数
	 * @param failFast
	 *            为true，当frame长度超过maxFrameLength时立即报TooLongFrameException异常，为false，读取完整个帧再报异常
	 */
	public HRDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment,
			int initialBytesToStrip, boolean failFast) {
		super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
	}

	@Override
	protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
//		byte[] data = new byte[in.readableBytes()];
//		in.readBytes(data);
//		System.out.println("门禁的完整报文="+ByteUtil.byteArrToHexString(data));
//		return null;
		
		
		if (in == null) {
			return null;
		}

		// System.out.println("#info 可读信息长度="+in.readableBytes());
		if (in.readableBytes() < HEADER_SIZE) {
			return null;
		}
		if (this.data != null) { // body不等于空说明上一次读到完整数据了
			this.header = in.readByte();
			if (this.header != 0x1B) {
				return null;
			}
			this.command = in.readByte();
			this.sequence = in.readByte();
			this.opcode = in.readByte();
			byte[] bLen = new byte[2];
			in.readBytes(bLen);
			this.dataLen = (short) (((bLen[1] << 8) | bLen[0] & 0xff));

			// this.dataLen = in.readShort();

		}

		if (in.readableBytes() < this.dataLen + BCC_SIZE) {
			this.data = null;
			return null;
		} else {
			this.data = new byte[this.dataLen];
			if (this.dataLen > 0) {
				in.readBytes(this.data);
			}
//			byte bcc = in.readByte();
//			byte tempBcc = 0;
//			for (byte b : this.data) {
//				tempBcc += b;
//			}
			// if(bcc!=tempBcc) {
			// throw new Exception("HR BCC Checkout failure!");
			// }
		}
		
		HRMessage message = new HRMessage(this.command, this.sequence, this.opcode, this.data);
		return message;
	}
}
